package com.example.demo.security.jwt;

import com.example.demo.entity.User;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import org.springframework.stereotype.Component;

import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;


@Component
public class JwtTokenUtil implements Serializable {

    //令牌配置属性
    private final JwtProperties jwtConfigProperties;

    public JwtTokenUtil(JwtProperties jwtConfigProperties) {
        this.jwtConfigProperties = jwtConfigProperties;
    }

    //根据用户生成令牌
    public String generateToken(User user, String authority) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("authority", authority);

        return Jwts.builder().addClaims(claims)
                .setSubject(user.getID())
                .setIssuedAt(new Date(System.currentTimeMillis()))
                .setExpiration(new Date(System.currentTimeMillis() + jwtConfigProperties.getValidity()))
                .signWith(SignatureAlgorithm.HS512, jwtConfigProperties.getSecret()).compact();
    }


    //从令牌获取用户名
    public String getUseridFromToken(String jwtToken) {
        return getClaimFromToken(jwtToken, Claims::getSubject);
    }

    //验证令牌有效性
    public boolean validateToken(String jwtToken, User user) {

        final String id = getUseridFromToken(jwtToken);
        return (id.equals(user.getID()) && !isTokenExpired(jwtToken) && Objects.equals(user.getToken(), jwtToken));
    }

    //获取令牌生成时间
    private Date getExpirationDateFromToken(String jwtToken) {
        return getClaimFromToken(jwtToken, Claims::getExpiration);
    }

    //从令牌获取Claim(身份信息)
    private <T> T getClaimFromToken(String jwtToken, Function<Claims, T> claimsResolver) {
        final Claims claims = getAllClaimsFromToken(jwtToken);
        return claimsResolver.apply(claims);
    }

    //从令牌获取全部Claim
    public Claims getAllClaimsFromToken(String jwtToken) {
        return Jwts.parser().setSigningKey(jwtConfigProperties.getSecret()).parseClaimsJws(jwtToken).getBody();
    }

    //检测令牌是否过期
    private boolean isTokenExpired(String jwtToken) {
        final Date expiration = getExpirationDateFromToken(jwtToken);
        return expiration.before(new Date());
    }


}

